﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace MatrixControls
{
	[DefaultEvent("Click")]
	public partial class Thumbnail : UserControl
	{
		private int box_width   = 100;
		private int box_padding = 5;
		private bool selected   = false;
		private bool separated  = true;
		private bool showborder = true;

		private static readonly int canvas_row    = 6;
		private static readonly int canvas_column = 9;
		private readonly int[] pixels = new int[canvas_row * canvas_column];

		private int canvas_width   = 0; // 画布宽度
		private int canvas_height  = 0; // 画布高度
		private int pixel_size     = 0; // 像素尺寸
		private int box_width_last = 0;

		private Color color_border;
		private readonly Color color_border_normal          = Color.FromArgb(200, 199, 197);
		private readonly Color color_border_hover           = Color.FromArgb(151, 149, 147);
		private readonly Color color_border_selected_normal = Color.FromArgb(183, 71, 42);
		private readonly Color color_border_selected_hover  = Color.FromArgb(169, 43, 26);


		public Thumbnail()
		{
			InitializeComponent();

			SetStyle(ControlStyles.AllPaintingInWmPaint, true);
			SetStyle(ControlStyles.UserPaint, true);

			color_border = color_border_normal;
			BoxWidth     = box_width;
			BoxPadding   = box_padding;
			
			for (int index = 0; index < canvas_row * canvas_column; index++)
			{
				pixels[index] = Color.White.ToArgb();
			}
		}


		#region 控件属性
		[Browsable(false)]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public new Padding Padding { get; set; }

		[Category("外观")]
		[Browsable(true)]
		[Description("缩略图宽度")]
		public int BoxWidth
		{
			get { return box_width; }
			set
			{
				box_width_last = box_width = value < 100 ? 100 : value;

				while ((box_width - (2 * box_padding)) % canvas_column != 0)
				{
					box_width--;
				}

				ResizeBox();
			}
		}

		[Category("外观")]
		[Browsable(true)]
		[Description("缩略图是否显示分隔线")]
		public bool Separated
		{
			get { return separated; }
			set
			{
				separated = value;

				Invalidate();
			}
		}

		[Category("布局")]
		[Browsable(true)]
		[Description("缩略图的内部距离")]
		public int BoxPadding
		{
			get { return box_padding; }
			set
			{
				box_padding = value;
				box_width = box_width_last;

				while ((box_width - (2 * box_padding)) % canvas_column != 0)
				{
					box_width--;
				}

				ResizeBox();
			}
		}

		[Category("数据")]
		[Description("缩略图索引序号")]
		public int Index { get; set; } = 0;

		[Category("行为")]
		[Browsable(true)]
		[Description("缩略图是否选中")]
		public bool Selected
		{
			get { return selected; }
			set
			{
				selected = value;
				color_border = selected ? color_border_selected_normal : color_border_normal;

				if (RectangleToScreen(ClientRectangle).Contains(MousePosition))
				{
					color_border = selected ? color_border_selected_hover : color_border_hover;
				}

				Invalidate();
			}
		}

		[Category("行为")]
		[Browsable(true)]
		[Description("缩略图是否显示边框")]
		public bool ShowBorder
		{
			get { return showborder; }
			set
			{
				showborder = value;

				Invalidate();
			}
		}
		#endregion


		#region 自定义函数
		/// <summary>
		/// 在指定位置绘制一个像素点
		/// </summary>
		/// <param name="index">索引下标</param>
		/// <param name="argb">argb 颜色值</param>
		public void DrawPixel(int index, int argb)
		{
			pixels[index] = argb;

			Invalidate();
		}

		/// <summary>
		/// 绘制画面全部像素点
		/// </summary>
		/// <param name="argbs_index">argb 颜色值序号数组</param>
		/// <param name="colors">argb 颜色数组</param>
		public void DrawPixels(int[] argbs_index, int[,] colors, bool single_color=false)
		{
			Color color;

			for (int index = 0; index < argbs_index.Length; index++)
			{
				if (single_color)
				{
					color = argbs_index[index] != 0 ? Color.Black : Color.White;
				}
				else
				{
					color = Color.FromArgb(
						colors[argbs_index[index], 0],
						colors[argbs_index[index], 1],
						colors[argbs_index[index], 2]
					);
				}

				pixels[index] = color.ToArgb();
			}

			Invalidate();
		}

		/// <summary>
		/// 重新计算画布和像素点尺寸
		/// </summary>
		private void ResizeBox()
		{
			canvas_width  = box_width - (2 * box_padding);
			pixel_size    = canvas_width / canvas_column;
			canvas_height = pixel_size * canvas_row;

			Width  = canvas_width + (2 * box_padding);
			Height = canvas_height + (2 * box_padding);

			Invalidate();
		}

		/// <summary>
		/// 绘制圆角矩形
		/// </summary>
		/// <param name="g"></param>
		/// <param name="pen"></param>
		/// <param name="rect"></param>
		/// <param name="radius"></param>
		private void DrawRoundedRect(Graphics g, Pen pen, Rectangle rect, int radius)
		{
			GraphicsPath gp = new GraphicsPath();

			gp.AddArc(rect.X, rect.Y, radius, radius, 180, 90);
			gp.AddArc(rect.X + rect.Width - radius, rect.Y, radius, radius, 270, 90);
			gp.AddArc(rect.X + rect.Width - radius, rect.Y + rect.Height - radius, radius, radius, 0, 90);
			gp.AddArc(rect.X, rect.Y + rect.Height - radius, radius, radius, 90, 90);
			gp.CloseAllFigures();

			g.DrawPath(pen, gp);
		}
		#endregion


		#region 窗体控件事件
		private void Thumbnail_MouseEnter(object sender, EventArgs e)
		{
			color_border = selected ? color_border_selected_hover : color_border_hover;

			Invalidate();
		}

		private void Thumbnail_MouseLeave(object sender, EventArgs e)
		{
			color_border = selected ? color_border_selected_normal : color_border_normal;

			Invalidate();
		}

		private void Thumbnail_SizeChanged(object sender, EventArgs e) { BoxWidth = Width; }

		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint(e);

			BufferedGraphicsContext buffer_context = BufferedGraphicsManager.Current;
			BufferedGraphics buffer = buffer_context.Allocate(e.Graphics, e.ClipRectangle);
			Graphics graphics = buffer.Graphics;

			graphics.Clear(SystemColors.Control);
			graphics.FillRectangle(new SolidBrush(Color.White), new Rectangle(3, 3, Width - 5, Height - 5));

			if (separated)
			{
				graphics.SmoothingMode = SmoothingMode.HighQuality;
			}

			int index, pos_x, pos_y, pen_width;

			for (int y = 0; y < canvas_column; y++)
			{
				for (int x = 0; x < canvas_row; x++)
				{
					index = y * canvas_row + x;
					pos_x = box_padding + (y * pixel_size);
					pos_y = box_padding + (x * pixel_size);

					graphics.FillRectangle(
						new SolidBrush(Color.FromArgb(pixels[index])),
						new Rectangle(pos_x, pos_y, pixel_size, pixel_size)
					);
				}
			}

			if (showborder)
			{
				graphics.SmoothingMode = SmoothingMode.HighQuality;
				pen_width = color_border == color_border_selected_hover ? 3 : 2;

				DrawRoundedRect(
					graphics,
					new Pen(color_border, pen_width),
					new Rectangle(2, 2, Width - 4, Height - 4),
					10
				);
			}

			buffer.Render(e.Graphics);
			buffer.Dispose();
			graphics.Dispose();
		}
		#endregion
	}
}
